﻿using System;
using System.Globalization;
using System.Linq;
using Viyi.Util.Codec;
using Xunit;
using Xunit.Abstractions;

namespace Viyi.Util.Test.Codec
{
    public class TestHexCodec
    {
        static readonly Random random = new Random();

        static byte[] CreateRandomData(int length)
        {
            byte[] data = new byte[length];
            random.NextBytes(data);
            return data;
        }

        readonly HexCodec hex = new HexCodec();
        readonly ITestOutputHelper output;

        public TestHexCodec(ITestOutputHelper output)
        {
            this.output = output;
        }

        [Fact]
        public void TestSimpleHexEncode()
        {
            byte[] data = CreateRandomData(random.Next(50, 100));
            var expect = BitConverter.ToString(data).Replace("-", string.Empty);
            Assert.Equal(expect, hex.Encode(data));

            var start = data.Length / 3;
            var count = data.Length / 2;
            expect = BitConverter.ToString(data, start, count).Replace("-", string.Empty);
            Assert.Equal(expect, hex.Encode(data, start, count));
        }

        [Fact]
        public void TestSimpleHexEncodeMore()
        {
            byte[][] data = new byte[random.Next(5, 10)][];
            for (var i = 0; i < data.Length; i++)
            {
                data[i] = new byte[random.Next(20, 50)];
                random.NextBytes(data[i]);
            }

            var expect = string.Join(
                string.Empty,
                data.Select(bytes => BitConverter.ToString(bytes)
                    .Replace("-", string.Empty)));

            Assert.Equal(expect, hex.Encode(data));
        }

        [Fact]
        public void TestLineBreak()
        {
            const int dataLength = 130;
            const int lineLength = 32;

            byte[] data = CreateRandomData(dataLength);
            var expect = BitConverter.ToString(data).Replace("-", string.Empty);

            var hexWithLineBreak = new HexCodec { LineLength = lineLength };
            var code = hexWithLineBreak.Encode(data);
            var lines = code.Split(new[] { hexWithLineBreak.EndOfLine }, StringSplitOptions.None);
            Assert.Equal(expect, string.Join(string.Empty, lines));

            var lineCount = (int) Math.Ceiling(dataLength * 2.0 / lineLength);
            Assert.Equal(lineCount, lines.Length);

            for (var i = lineCount - 2; i >= 0; i--)
            {
                Assert.Equal(lineLength, lines[i].Length);
            }
            var lastLineLength = (dataLength * 2 - 1) % lineLength + 1;
            Assert.Equal(lastLineLength, lines[lineCount - 1].Length);
        }

        [Fact]
        public void TestSimpleHexDecode()
        {
            byte[] data = new byte[random.Next(50, 100)];
            random.NextBytes(data);
            var hexCode = BitConverter.ToString(data).Replace("-", string.Empty);

            Assert.Equal(data, hex.Decode(hexCode));
        }

        [Fact]
        public void TestSimpleHexDecodeWithSegment()
        {
            // code should be:  00ee5ab9021f653e 8a3d4c42 b4db9b9a0d162cfe00e0
            const string code = "0ee5ab9-21f653e-8a3d4c42-b4db9b9a-d162cfe-0e0";
            const string compact = "00ee5ab9021f653e8a3d4c42b4db9b9a0d162cfe00e0";

            // generate expect bytes with simple algorithm
            Assert.Equal(0, compact.Length % 2);
            byte[] expect = new byte[compact.Length / 2];
            for (var i = 0; i < expect.Length; i++)
            {
                expect[i] = byte.Parse(compact.Substring(i * 2, 2), NumberStyles.HexNumber);
            }

            byte[] result = hex.Decode(code);

            Assert.Equal(expect, result);
        }
    }
}
